package com.lysj.admin.master.common.spring.mpbase;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lysj.admin.master.common.CommonConstant;
import com.lysj.admin.master.common.spring.mpbase.condition.MpPredicate;
import com.lysj.admin.master.common.spring.mpbase.condition.MpPredicateDTO;
import com.lysj.admin.master.common.spring.mpbase.condition.NotField;
import com.lysj.admin.master.common.spring.pagination.PageRequestDTO;
import com.lysj.admin.master.common.web.ParamUtil;
import com.lysj.admin.master.common.web.SelectItem;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Created by zk on 2019-12-24 15:43
 * @description
 */
public class MyService<M extends BaseMapper<E>, E extends IdEntity> extends ServiceImpl<M,E> {


    private static Cache<Class,String[]> voNameCache = CacheUtil.newLRUCache(100);

    public <V> List<V> voList(QueryWrapper<E> wrapper,Class<V> voClass) {
        wrapper = selectWrapper(wrapper,voClass);
        List<E> list = this.list(wrapper);
        List<V> voList = new LinkedList<>();
        for (E e : list) {
            V v = ReflectUtil.newInstanceIfPossible(voClass);
            BeanUtil.copyProperties(e,v);
            voList.add(v);
        }
        return voList;
    }

    public Page<E> pageList(PageRequestDTO condition){
        QueryWrapper<E> wrapper = createWrapper(condition);
        if("asc".equalsIgnoreCase(condition.getPageOrder())){
            wrapper.orderByAsc(StrUtil.toUnderlineCase(condition.getPageSort()));
        }else {
            wrapper.orderByDesc(StrUtil.toUnderlineCase(condition.getPageSort()));
        }
        return this.page(new Page<>(condition.getPageNumber(), condition.getPageSize()), wrapper);
    }

    public <V> Page<E> pageList(PageRequestDTO condition,Class<V> voClass){
        QueryWrapper<E> wrapper = createWrapper(condition);
        wrapper = selectWrapper(wrapper,voClass);
        if("asc".equalsIgnoreCase(condition.getPageOrder())){
            wrapper.orderByAsc(StrUtil.toUnderlineCase(condition.getPageSort()));
        }else {
            wrapper.orderByDesc(StrUtil.toUnderlineCase(condition.getPageSort()));
        }
        return this.page(new Page<>(condition.getPageNumber(), condition.getPageSize()), wrapper);
    }

    protected QueryWrapper<E> selectWrapper(QueryWrapper<E> wrapper,Class voClass){
        String[] fieldName = voNameCache.get(voClass, () -> {
            Field[] fs = voClass.getDeclaredFields();
            List<String> nameList = new LinkedList<>();
            for (Field f : fs) {
                if(f.getAnnotation(NotField.class) == null){
                    String selectName = StrUtil.toUnderlineCase(f.getName());
                    nameList.add(selectName);
                }
            }
            return ArrayUtil.toArray(nameList, String.class);
        });
        return wrapper.select(fieldName);
    }

    protected QueryWrapper<E> createWrapper(Object condition){
        QueryWrapper<E> queryWrapper = new QueryWrapper<>();
        // 得到类对象
        Class cls = condition.getClass();
        if(PageRequestDTO.class.equals(cls)){
            return queryWrapper;
        }
        /* 得到类中的所有属性集合 */
        Field[] fs = cls.getDeclaredFields();
        for (Field f : fs) {
            f.setAccessible(true);
            Object val = ReflectUtil.getFieldValue(condition, f);
            if(val == null || val.toString().equals("")){
                continue;
            }
            MpPredicate annotation = f.getAnnotation(MpPredicate.class);
            if (annotation != null) {
                //若没有额外填写字段名，默认属性名为要查询的字段名
                String propertyName = ParamUtil.isBlank(annotation.property()) ? f.getName() : annotation.property();
                propertyName = StrUtil.toUnderlineCase(propertyName);
                MpPredicateDTO dto = new MpPredicateDTO(propertyName,val);
                annotation.value().getPredicateFunc().accept(queryWrapper,dto);
            }
        }
        return queryWrapper;
    }


    public List<SelectItem<String, String>> selectItem() {
//        List<E> all = this.lambdaQuery()
//                .select(IdEntity::getId, IdEntity::getName)
//                .eq(IdEntity::getDelFlag, CommonConstant.NORMAL_FLAG)
//                .list();
        QueryWrapper<E> wrapper = new QueryWrapper<>();
        wrapper.select(CommonConstant.ID_NAME,CommonConstant.NAME_NAME).eq(CommonConstant.DEL_FLAG_NAME,CommonConstant.NORMAL_FLAG);
        List<E> all = this.list(wrapper);
        List<SelectItem<String, String>> selectItems = all.parallelStream()
                .map(e -> new SelectItem<>(e.getId(), e.getName()))
                .collect(Collectors.toList());
        return selectItems;
    }


}
